// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2013 Christian Seiler <christian@iwakd.de>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"

#include <Eigen/CXX11/Tensor>
#include <Eigen/CXX11/TensorSymmetry>

#include <map>
#include <set>

using Eigen::AntiHermiticity;
using Eigen::AntiSymmetry;
using Eigen::DynamicSGroup;
using Eigen::Hermiticity;
using Eigen::SGroup;
using Eigen::StaticSGroup;
using Eigen::Symmetry;
using Eigen::Tensor;

using Eigen::ConjugationFlag;
using Eigen::GlobalImagFlag;
using Eigen::GlobalRealFlag;
using Eigen::GlobalZeroFlag;
using Eigen::NegationFlag;

// helper function to determine if the compiler intantiated a static
// or dynamic symmetry group
template <typename... Sym>
bool isDynGroup(StaticSGroup<Sym...> const& dummy) {
  (void)dummy;
  return false;
}

bool isDynGroup(DynamicSGroup const& dummy) {
  (void)dummy;
  return true;
}

// helper class for checking that the symmetry groups are correct
struct checkIdx {
  template <typename ArrType>
  static inline int doCheck_(ArrType e, int flags, int dummy, std::set<uint64_t>& found,
                             std::map<uint64_t, int> const& expected) {
    // use decimal representation of value
    uint64_t value = e[0];
    for (std::size_t i = 1; i < e.size(); i++) value = value * 10 + e[i];

    // we want to make sure that we find each element
    auto it = expected.find(value);
    VERIFY((it != expected.end()));
    VERIFY_IS_EQUAL(it->second, flags);

    // we want to make sure we only have each element once;
    // set::insert returns true for the second part of the pair
    // if the element was really inserted and not already there
    auto p = found.insert(value);
    VERIFY((p.second));

    return dummy;
  }

  static inline int run(std::vector<int> e, int flags, int dummy, std::set<uint64_t>& found,
                        std::map<uint64_t, int> const& expected) {
    return doCheck_(e, flags, dummy, found, expected);
  }

  template <std::size_t N>
  static inline int run(std::array<int, N> e, int flags, int dummy, std::set<uint64_t>& found,
                        std::map<uint64_t, int> const& expected) {
    return doCheck_(e, flags, dummy, found, expected);
  }
};

static void test_symgroups_static() {
  std::array<int, 7> identity{{0, 1, 2, 3, 4, 5, 6}};

  // Simple static symmetry group
  StaticSGroup<AntiSymmetry<0, 1>, Hermiticity<0, 2>> group;

  std::set<uint64_t> found;
  std::map<uint64_t, int> expected;
  expected[123456] = 0;
  expected[1023456] = NegationFlag;
  expected[2103456] = ConjugationFlag;
  expected[1203456] = ConjugationFlag | NegationFlag;
  expected[2013456] = ConjugationFlag | NegationFlag;
  expected[213456] = ConjugationFlag;

  VERIFY_IS_EQUAL(group.size(), 6u);
  VERIFY_IS_EQUAL(group.globalFlags(), GlobalImagFlag);
  group.apply<checkIdx, int>(identity, 0, found, expected);
  VERIFY_IS_EQUAL(found.size(), 6u);
}

static void test_symgroups_dynamic() {
  std::vector<int> identity;
  for (int i = 0; i <= 6; i++) identity.push_back(i);

  // Simple dynamic symmetry group
  DynamicSGroup group;
  group.add(0, 1, NegationFlag);
  group.add(0, 2, ConjugationFlag);

  VERIFY_IS_EQUAL(group.size(), 6u);
  VERIFY_IS_EQUAL(group.globalFlags(), GlobalImagFlag);

  std::set<uint64_t> found;
  std::map<uint64_t, int> expected;
  expected[123456] = 0;
  expected[1023456] = NegationFlag;
  expected[2103456] = ConjugationFlag;
  expected[1203456] = ConjugationFlag | NegationFlag;
  expected[2013456] = ConjugationFlag | NegationFlag;
  expected[213456] = ConjugationFlag;

  VERIFY_IS_EQUAL(group.size(), 6u);
  VERIFY_IS_EQUAL(group.globalFlags(), GlobalImagFlag);
  group.apply<checkIdx, int>(identity, 0, found, expected);
  VERIFY_IS_EQUAL(found.size(), 6u);
}

static void test_symgroups_selection() {
  std::array<int, 7> identity7{{0, 1, 2, 3, 4, 5, 6}};
  std::array<int, 10> identity10{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};

  {
    // Do the same test as in test_symgroups_static but
    // require selection via SGroup
    SGroup<AntiSymmetry<0, 1>, Hermiticity<0, 2>> group;

    std::set<uint64_t> found;
    std::map<uint64_t, int> expected;
    expected[123456] = 0;
    expected[1023456] = NegationFlag;
    expected[2103456] = ConjugationFlag;
    expected[1203456] = ConjugationFlag | NegationFlag;
    expected[2013456] = ConjugationFlag | NegationFlag;
    expected[213456] = ConjugationFlag;

    VERIFY(!isDynGroup(group));
    VERIFY_IS_EQUAL(group.size(), 6u);
    VERIFY_IS_EQUAL(group.globalFlags(), GlobalImagFlag);
    group.apply<checkIdx, int>(identity7, 0, found, expected);
    VERIFY_IS_EQUAL(found.size(), 6u);
  }

  {
    // simple factorizing group: 5 generators, 2^5 = 32 elements
    // selection should make this dynamic, although static group
    // can still be reasonably generated
    SGroup<Symmetry<0, 1>, Symmetry<2, 3>, Symmetry<4, 5>, Symmetry<6, 7>, Symmetry<8, 9>> group;

    std::set<uint64_t> found;
    std::map<uint64_t, int> expected;
    expected[123456789] = 0;
    expected[123456798] = 0;
    expected[123457689] = 0;
    expected[123457698] = 0;
    expected[123546789] = 0;
    expected[123546798] = 0;
    expected[123547689] = 0;
    expected[123547698] = 0;
    expected[132456789] = 0;
    expected[132456798] = 0;
    expected[132457689] = 0;
    expected[132457698] = 0;
    expected[132546789] = 0;
    expected[132546798] = 0;
    expected[132547689] = 0;
    expected[132547698] = 0;
    expected[1023456789] = 0;
    expected[1023456798] = 0;
    expected[1023457689] = 0;
    expected[1023457698] = 0;
    expected[1023546789] = 0;
    expected[1023546798] = 0;
    expected[1023547689] = 0;
    expected[1023547698] = 0;
    expected[1032456789] = 0;
    expected[1032456798] = 0;
    expected[1032457689] = 0;
    expected[1032457698] = 0;
    expected[1032546789] = 0;
    expected[1032546798] = 0;
    expected[1032547689] = 0;
    expected[1032547698] = 0;

    VERIFY(isDynGroup(group));
    VERIFY_IS_EQUAL(group.size(), 32u);
    VERIFY_IS_EQUAL(group.globalFlags(), 0);
    group.apply<checkIdx, int>(identity10, 0, found, expected);
    VERIFY_IS_EQUAL(found.size(), 32u);

    // no verify that we could also generate a static group
    // with these generators
    found.clear();
    StaticSGroup<Symmetry<0, 1>, Symmetry<2, 3>, Symmetry<4, 5>, Symmetry<6, 7>, Symmetry<8, 9>> group_static;
    VERIFY_IS_EQUAL(group_static.size(), 32u);
    VERIFY_IS_EQUAL(group_static.globalFlags(), 0);
    group_static.apply<checkIdx, int>(identity10, 0, found, expected);
    VERIFY_IS_EQUAL(found.size(), 32u);
  }

  {
    // try to create a HUGE group
    SGroup<Symmetry<0, 1>, Symmetry<1, 2>, Symmetry<2, 3>, Symmetry<3, 4>, Symmetry<4, 5>, Symmetry<5, 6>> group;

    std::set<uint64_t> found;
    uint64_t pre_expected[5040] = {
        123456,  1023456, 213456,  2013456, 1203456, 2103456, 132456,  1032456, 312456,  3012456, 1302456, 3102456,
        231456,  2031456, 321456,  3021456, 2301456, 3201456, 1230456, 2130456, 1320456, 3120456, 2310456, 3210456,
        124356,  1024356, 214356,  2014356, 1204356, 2104356, 142356,  1042356, 412356,  4012356, 1402356, 4102356,
        241356,  2041356, 421356,  4021356, 2401356, 4201356, 1240356, 2140356, 1420356, 4120356, 2410356, 4210356,
        134256,  1034256, 314256,  3014256, 1304256, 3104256, 143256,  1043256, 413256,  4013256, 1403256, 4103256,
        341256,  3041256, 431256,  4031256, 3401256, 4301256, 1340256, 3140256, 1430256, 4130256, 3410256, 4310256,
        234156,  2034156, 324156,  3024156, 2304156, 3204156, 243156,  2043156, 423156,  4023156, 2403156, 4203156,
        342156,  3042156, 432156,  4032156, 3402156, 4302156, 2340156, 3240156, 2430156, 4230156, 3420156, 4320156,
        1234056, 2134056, 1324056, 3124056, 2314056, 3214056, 1243056, 2143056, 1423056, 4123056, 2413056, 4213056,
        1342056, 3142056, 1432056, 4132056, 3412056, 4312056, 2341056, 3241056, 2431056, 4231056, 3421056, 4321056,
        123546,  1023546, 213546,  2013546, 1203546, 2103546, 132546,  1032546, 312546,  3012546, 1302546, 3102546,
        231546,  2031546, 321546,  3021546, 2301546, 3201546, 1230546, 2130546, 1320546, 3120546, 2310546, 3210546,
        125346,  1025346, 215346,  2015346, 1205346, 2105346, 152346,  1052346, 512346,  5012346, 1502346, 5102346,
        251346,  2051346, 521346,  5021346, 2501346, 5201346, 1250346, 2150346, 1520346, 5120346, 2510346, 5210346,
        135246,  1035246, 315246,  3015246, 1305246, 3105246, 153246,  1053246, 513246,  5013246, 1503246, 5103246,
        351246,  3051246, 531246,  5031246, 3501246, 5301246, 1350246, 3150246, 1530246, 5130246, 3510246, 5310246,
        235146,  2035146, 325146,  3025146, 2305146, 3205146, 253146,  2053146, 523146,  5023146, 2503146, 5203146,
        352146,  3052146, 532146,  5032146, 3502146, 5302146, 2350146, 3250146, 2530146, 5230146, 3520146, 5320146,
        1235046, 2135046, 1325046, 3125046, 2315046, 3215046, 1253046, 2153046, 1523046, 5123046, 2513046, 5213046,
        1352046, 3152046, 1532046, 5132046, 3512046, 5312046, 2351046, 3251046, 2531046, 5231046, 3521046, 5321046,
        124536,  1024536, 214536,  2014536, 1204536, 2104536, 142536,  1042536, 412536,  4012536, 1402536, 4102536,
        241536,  2041536, 421536,  4021536, 2401536, 4201536, 1240536, 2140536, 1420536, 4120536, 2410536, 4210536,
        125436,  1025436, 215436,  2015436, 1205436, 2105436, 152436,  1052436, 512436,  5012436, 1502436, 5102436,
        251436,  2051436, 521436,  5021436, 2501436, 5201436, 1250436, 2150436, 1520436, 5120436, 2510436, 5210436,
        145236,  1045236, 415236,  4015236, 1405236, 4105236, 154236,  1054236, 514236,  5014236, 1504236, 5104236,
        451236,  4051236, 541236,  5041236, 4501236, 5401236, 1450236, 4150236, 1540236, 5140236, 4510236, 5410236,
        245136,  2045136, 425136,  4025136, 2405136, 4205136, 254136,  2054136, 524136,  5024136, 2504136, 5204136,
        452136,  4052136, 542136,  5042136, 4502136, 5402136, 2450136, 4250136, 2540136, 5240136, 4520136, 5420136,
        1245036, 2145036, 1425036, 4125036, 2415036, 4215036, 1254036, 2154036, 1524036, 5124036, 2514036, 5214036,
        1452036, 4152036, 1542036, 5142036, 4512036, 5412036, 2451036, 4251036, 2541036, 5241036, 4521036, 5421036,
        134526,  1034526, 314526,  3014526, 1304526, 3104526, 143526,  1043526, 413526,  4013526, 1403526, 4103526,
        341526,  3041526, 431526,  4031526, 3401526, 4301526, 1340526, 3140526, 1430526, 4130526, 3410526, 4310526,
        135426,  1035426, 315426,  3015426, 1305426, 3105426, 153426,  1053426, 513426,  5013426, 1503426, 5103426,
        351426,  3051426, 531426,  5031426, 3501426, 5301426, 1350426, 3150426, 1530426, 5130426, 3510426, 5310426,
        145326,  1045326, 415326,  4015326, 1405326, 4105326, 154326,  1054326, 514326,  5014326, 1504326, 5104326,
        451326,  4051326, 541326,  5041326, 4501326, 5401326, 1450326, 4150326, 1540326, 5140326, 4510326, 5410326,
        345126,  3045126, 435126,  4035126, 3405126, 4305126, 354126,  3054126, 534126,  5034126, 3504126, 5304126,
        453126,  4053126, 543126,  5043126, 4503126, 5403126, 3450126, 4350126, 3540126, 5340126, 4530126, 5430126,
        1345026, 3145026, 1435026, 4135026, 3415026, 4315026, 1354026, 3154026, 1534026, 5134026, 3514026, 5314026,
        1453026, 4153026, 1543026, 5143026, 4513026, 5413026, 3451026, 4351026, 3541026, 5341026, 4531026, 5431026,
        234516,  2034516, 324516,  3024516, 2304516, 3204516, 243516,  2043516, 423516,  4023516, 2403516, 4203516,
        342516,  3042516, 432516,  4032516, 3402516, 4302516, 2340516, 3240516, 2430516, 4230516, 3420516, 4320516,
        235416,  2035416, 325416,  3025416, 2305416, 3205416, 253416,  2053416, 523416,  5023416, 2503416, 5203416,
        352416,  3052416, 532416,  5032416, 3502416, 5302416, 2350416, 3250416, 2530416, 5230416, 3520416, 5320416,
        245316,  2045316, 425316,  4025316, 2405316, 4205316, 254316,  2054316, 524316,  5024316, 2504316, 5204316,
        452316,  4052316, 542316,  5042316, 4502316, 5402316, 2450316, 4250316, 2540316, 5240316, 4520316, 5420316,
        345216,  3045216, 435216,  4035216, 3405216, 4305216, 354216,  3054216, 534216,  5034216, 3504216, 5304216,
        453216,  4053216, 543216,  5043216, 4503216, 5403216, 3450216, 4350216, 3540216, 5340216, 4530216, 5430216,
        2345016, 3245016, 2435016, 4235016, 3425016, 4325016, 2354016, 3254016, 2534016, 5234016, 3524016, 5324016,
        2453016, 4253016, 2543016, 5243016, 4523016, 5423016, 3452016, 4352016, 3542016, 5342016, 4532016, 5432016,
        1234506, 2134506, 1324506, 3124506, 2314506, 3214506, 1243506, 2143506, 1423506, 4123506, 2413506, 4213506,
        1342506, 3142506, 1432506, 4132506, 3412506, 4312506, 2341506, 3241506, 2431506, 4231506, 3421506, 4321506,
        1235406, 2135406, 1325406, 3125406, 2315406, 3215406, 1253406, 2153406, 1523406, 5123406, 2513406, 5213406,
        1352406, 3152406, 1532406, 5132406, 3512406, 5312406, 2351406, 3251406, 2531406, 5231406, 3521406, 5321406,
        1245306, 2145306, 1425306, 4125306, 2415306, 4215306, 1254306, 2154306, 1524306, 5124306, 2514306, 5214306,
        1452306, 4152306, 1542306, 5142306, 4512306, 5412306, 2451306, 4251306, 2541306, 5241306, 4521306, 5421306,
        1345206, 3145206, 1435206, 4135206, 3415206, 4315206, 1354206, 3154206, 1534206, 5134206, 3514206, 5314206,
        1453206, 4153206, 1543206, 5143206, 4513206, 5413206, 3451206, 4351206, 3541206, 5341206, 4531206, 5431206,
        2345106, 3245106, 2435106, 4235106, 3425106, 4325106, 2354106, 3254106, 2534106, 5234106, 3524106, 5324106,
        2453106, 4253106, 2543106, 5243106, 4523106, 5423106, 3452106, 4352106, 3542106, 5342106, 4532106, 5432106,
        123465,  1023465, 213465,  2013465, 1203465, 2103465, 132465,  1032465, 312465,  3012465, 1302465, 3102465,
        231465,  2031465, 321465,  3021465, 2301465, 3201465, 1230465, 2130465, 1320465, 3120465, 2310465, 3210465,
        124365,  1024365, 214365,  2014365, 1204365, 2104365, 142365,  1042365, 412365,  4012365, 1402365, 4102365,
        241365,  2041365, 421365,  4021365, 2401365, 4201365, 1240365, 2140365, 1420365, 4120365, 2410365, 4210365,
        134265,  1034265, 314265,  3014265, 1304265, 3104265, 143265,  1043265, 413265,  4013265, 1403265, 4103265,
        341265,  3041265, 431265,  4031265, 3401265, 4301265, 1340265, 3140265, 1430265, 4130265, 3410265, 4310265,
        234165,  2034165, 324165,  3024165, 2304165, 3204165, 243165,  2043165, 423165,  4023165, 2403165, 4203165,
        342165,  3042165, 432165,  4032165, 3402165, 4302165, 2340165, 3240165, 2430165, 4230165, 3420165, 4320165,
        1234065, 2134065, 1324065, 3124065, 2314065, 3214065, 1243065, 2143065, 1423065, 4123065, 2413065, 4213065,
        1342065, 3142065, 1432065, 4132065, 3412065, 4312065, 2341065, 3241065, 2431065, 4231065, 3421065, 4321065,
        123645,  1023645, 213645,  2013645, 1203645, 2103645, 132645,  1032645, 312645,  3012645, 1302645, 3102645,
        231645,  2031645, 321645,  3021645, 2301645, 3201645, 1230645, 2130645, 1320645, 3120645, 2310645, 3210645,
        126345,  1026345, 216345,  2016345, 1206345, 2106345, 162345,  1062345, 612345,  6012345, 1602345, 6102345,
        261345,  2061345, 621345,  6021345, 2601345, 6201345, 1260345, 2160345, 1620345, 6120345, 2610345, 6210345,
        136245,  1036245, 316245,  3016245, 1306245, 3106245, 163245,  1063245, 613245,  6013245, 1603245, 6103245,
        361245,  3061245, 631245,  6031245, 3601245, 6301245, 1360245, 3160245, 1630245, 6130245, 3610245, 6310245,
        236145,  2036145, 326145,  3026145, 2306145, 3206145, 263145,  2063145, 623145,  6023145, 2603145, 6203145,
        362145,  3062145, 632145,  6032145, 3602145, 6302145, 2360145, 3260145, 2630145, 6230145, 3620145, 6320145,
        1236045, 2136045, 1326045, 3126045, 2316045, 3216045, 1263045, 2163045, 1623045, 6123045, 2613045, 6213045,
        1362045, 3162045, 1632045, 6132045, 3612045, 6312045, 2361045, 3261045, 2631045, 6231045, 3621045, 6321045,
        124635,  1024635, 214635,  2014635, 1204635, 2104635, 142635,  1042635, 412635,  4012635, 1402635, 4102635,
        241635,  2041635, 421635,  4021635, 2401635, 4201635, 1240635, 2140635, 1420635, 4120635, 2410635, 4210635,
        126435,  1026435, 216435,  2016435, 1206435, 2106435, 162435,  1062435, 612435,  6012435, 1602435, 6102435,
        261435,  2061435, 621435,  6021435, 2601435, 6201435, 1260435, 2160435, 1620435, 6120435, 2610435, 6210435,
        146235,  1046235, 416235,  4016235, 1406235, 4106235, 164235,  1064235, 614235,  6014235, 1604235, 6104235,
        461235,  4061235, 641235,  6041235, 4601235, 6401235, 1460235, 4160235, 1640235, 6140235, 4610235, 6410235,
        246135,  2046135, 426135,  4026135, 2406135, 4206135, 264135,  2064135, 624135,  6024135, 2604135, 6204135,
        462135,  4062135, 642135,  6042135, 4602135, 6402135, 2460135, 4260135, 2640135, 6240135, 4620135, 6420135,
        1246035, 2146035, 1426035, 4126035, 2416035, 4216035, 1264035, 2164035, 1624035, 6124035, 2614035, 6214035,
        1462035, 4162035, 1642035, 6142035, 4612035, 6412035, 2461035, 4261035, 2641035, 6241035, 4621035, 6421035,
        134625,  1034625, 314625,  3014625, 1304625, 3104625, 143625,  1043625, 413625,  4013625, 1403625, 4103625,
        341625,  3041625, 431625,  4031625, 3401625, 4301625, 1340625, 3140625, 1430625, 4130625, 3410625, 4310625,
        136425,  1036425, 316425,  3016425, 1306425, 3106425, 163425,  1063425, 613425,  6013425, 1603425, 6103425,
        361425,  3061425, 631425,  6031425, 3601425, 6301425, 1360425, 3160425, 1630425, 6130425, 3610425, 6310425,
        146325,  1046325, 416325,  4016325, 1406325, 4106325, 164325,  1064325, 614325,  6014325, 1604325, 6104325,
        461325,  4061325, 641325,  6041325, 4601325, 6401325, 1460325, 4160325, 1640325, 6140325, 4610325, 6410325,
        346125,  3046125, 436125,  4036125, 3406125, 4306125, 364125,  3064125, 634125,  6034125, 3604125, 6304125,
        463125,  4063125, 643125,  6043125, 4603125, 6403125, 3460125, 4360125, 3640125, 6340125, 4630125, 6430125,
        1346025, 3146025, 1436025, 4136025, 3416025, 4316025, 1364025, 3164025, 1634025, 6134025, 3614025, 6314025,
        1463025, 4163025, 1643025, 6143025, 4613025, 6413025, 3461025, 4361025, 3641025, 6341025, 4631025, 6431025,
        234615,  2034615, 324615,  3024615, 2304615, 3204615, 243615,  2043615, 423615,  4023615, 2403615, 4203615,
        342615,  3042615, 432615,  4032615, 3402615, 4302615, 2340615, 3240615, 2430615, 4230615, 3420615, 4320615,
        236415,  2036415, 326415,  3026415, 2306415, 3206415, 263415,  2063415, 623415,  6023415, 2603415, 6203415,
        362415,  3062415, 632415,  6032415, 3602415, 6302415, 2360415, 3260415, 2630415, 6230415, 3620415, 6320415,
        246315,  2046315, 426315,  4026315, 2406315, 4206315, 264315,  2064315, 624315,  6024315, 2604315, 6204315,
        462315,  4062315, 642315,  6042315, 4602315, 6402315, 2460315, 4260315, 2640315, 6240315, 4620315, 6420315,
        346215,  3046215, 436215,  4036215, 3406215, 4306215, 364215,  3064215, 634215,  6034215, 3604215, 6304215,
        463215,  4063215, 643215,  6043215, 4603215, 6403215, 3460215, 4360215, 3640215, 6340215, 4630215, 6430215,
        2346015, 3246015, 2436015, 4236015, 3426015, 4326015, 2364015, 3264015, 2634015, 6234015, 3624015, 6324015,
        2463015, 4263015, 2643015, 6243015, 4623015, 6423015, 3462015, 4362015, 3642015, 6342015, 4632015, 6432015,
        1234605, 2134605, 1324605, 3124605, 2314605, 3214605, 1243605, 2143605, 1423605, 4123605, 2413605, 4213605,
        1342605, 3142605, 1432605, 4132605, 3412605, 4312605, 2341605, 3241605, 2431605, 4231605, 3421605, 4321605,
        1236405, 2136405, 1326405, 3126405, 2316405, 3216405, 1263405, 2163405, 1623405, 6123405, 2613405, 6213405,
        1362405, 3162405, 1632405, 6132405, 3612405, 6312405, 2361405, 3261405, 2631405, 6231405, 3621405, 6321405,
        1246305, 2146305, 1426305, 4126305, 2416305, 4216305, 1264305, 2164305, 1624305, 6124305, 2614305, 6214305,
        1462305, 4162305, 1642305, 6142305, 4612305, 6412305, 2461305, 4261305, 2641305, 6241305, 4621305, 6421305,
        1346205, 3146205, 1436205, 4136205, 3416205, 4316205, 1364205, 3164205, 1634205, 6134205, 3614205, 6314205,
        1463205, 4163205, 1643205, 6143205, 4613205, 6413205, 3461205, 4361205, 3641205, 6341205, 4631205, 6431205,
        2346105, 3246105, 2436105, 4236105, 3426105, 4326105, 2364105, 3264105, 2634105, 6234105, 3624105, 6324105,
        2463105, 4263105, 2643105, 6243105, 4623105, 6423105, 3462105, 4362105, 3642105, 6342105, 4632105, 6432105,
        123564,  1023564, 213564,  2013564, 1203564, 2103564, 132564,  1032564, 312564,  3012564, 1302564, 3102564,
        231564,  2031564, 321564,  3021564, 2301564, 3201564, 1230564, 2130564, 1320564, 3120564, 2310564, 3210564,
        125364,  1025364, 215364,  2015364, 1205364, 2105364, 152364,  1052364, 512364,  5012364, 1502364, 5102364,
        251364,  2051364, 521364,  5021364, 2501364, 5201364, 1250364, 2150364, 1520364, 5120364, 2510364, 5210364,
        135264,  1035264, 315264,  3015264, 1305264, 3105264, 153264,  1053264, 513264,  5013264, 1503264, 5103264,
        351264,  3051264, 531264,  5031264, 3501264, 5301264, 1350264, 3150264, 1530264, 5130264, 3510264, 5310264,
        235164,  2035164, 325164,  3025164, 2305164, 3205164, 253164,  2053164, 523164,  5023164, 2503164, 5203164,
        352164,  3052164, 532164,  5032164, 3502164, 5302164, 2350164, 3250164, 2530164, 5230164, 3520164, 5320164,
        1235064, 2135064, 1325064, 3125064, 2315064, 3215064, 1253064, 2153064, 1523064, 5123064, 2513064, 5213064,
        1352064, 3152064, 1532064, 5132064, 3512064, 5312064, 2351064, 3251064, 2531064, 5231064, 3521064, 5321064,
        123654,  1023654, 213654,  2013654, 1203654, 2103654, 132654,  1032654, 312654,  3012654, 1302654, 3102654,
        231654,  2031654, 321654,  3021654, 2301654, 3201654, 1230654, 2130654, 1320654, 3120654, 2310654, 3210654,
        126354,  1026354, 216354,  2016354, 1206354, 2106354, 162354,  1062354, 612354,  6012354, 1602354, 6102354,
        261354,  2061354, 621354,  6021354, 2601354, 6201354, 1260354, 2160354, 1620354, 6120354, 2610354, 6210354,
        136254,  1036254, 316254,  3016254, 1306254, 3106254, 163254,  1063254, 613254,  6013254, 1603254, 6103254,
        361254,  3061254, 631254,  6031254, 3601254, 6301254, 1360254, 3160254, 1630254, 6130254, 3610254, 6310254,
        236154,  2036154, 326154,  3026154, 2306154, 3206154, 263154,  2063154, 623154,  6023154, 2603154, 6203154,
        362154,  3062154, 632154,  6032154, 3602154, 6302154, 2360154, 3260154, 2630154, 6230154, 3620154, 6320154,
        1236054, 2136054, 1326054, 3126054, 2316054, 3216054, 1263054, 2163054, 1623054, 6123054, 2613054, 6213054,
        1362054, 3162054, 1632054, 6132054, 3612054, 6312054, 2361054, 3261054, 2631054, 6231054, 3621054, 6321054,
        125634,  1025634, 215634,  2015634, 1205634, 2105634, 152634,  1052634, 512634,  5012634, 1502634, 5102634,
        251634,  2051634, 521634,  5021634, 2501634, 5201634, 1250634, 2150634, 1520634, 5120634, 2510634, 5210634,
        126534,  1026534, 216534,  2016534, 1206534, 2106534, 162534,  1062534, 612534,  6012534, 1602534, 6102534,
        261534,  2061534, 621534,  6021534, 2601534, 6201534, 1260534, 2160534, 1620534, 6120534, 2610534, 6210534,
        156234,  1056234, 516234,  5016234, 1506234, 5106234, 165234,  1065234, 615234,  6015234, 1605234, 6105234,
        561234,  5061234, 651234,  6051234, 5601234, 6501234, 1560234, 5160234, 1650234, 6150234, 5610234, 6510234,
        256134,  2056134, 526134,  5026134, 2506134, 5206134, 265134,  2065134, 625134,  6025134, 2605134, 6205134,
        562134,  5062134, 652134,  6052134, 5602134, 6502134, 2560134, 5260134, 2650134, 6250134, 5620134, 6520134,
        1256034, 2156034, 1526034, 5126034, 2516034, 5216034, 1265034, 2165034, 1625034, 6125034, 2615034, 6215034,
        1562034, 5162034, 1652034, 6152034, 5612034, 6512034, 2561034, 5261034, 2651034, 6251034, 5621034, 6521034,
        135624,  1035624, 315624,  3015624, 1305624, 3105624, 153624,  1053624, 513624,  5013624, 1503624, 5103624,
        351624,  3051624, 531624,  5031624, 3501624, 5301624, 1350624, 3150624, 1530624, 5130624, 3510624, 5310624,
        136524,  1036524, 316524,  3016524, 1306524, 3106524, 163524,  1063524, 613524,  6013524, 1603524, 6103524,
        361524,  3061524, 631524,  6031524, 3601524, 6301524, 1360524, 3160524, 1630524, 6130524, 3610524, 6310524,
        156324,  1056324, 516324,  5016324, 1506324, 5106324, 165324,  1065324, 615324,  6015324, 1605324, 6105324,
        561324,  5061324, 651324,  6051324, 5601324, 6501324, 1560324, 5160324, 1650324, 6150324, 5610324, 6510324,
        356124,  3056124, 536124,  5036124, 3506124, 5306124, 365124,  3065124, 635124,  6035124, 3605124, 6305124,
        563124,  5063124, 653124,  6053124, 5603124, 6503124, 3560124, 5360124, 3650124, 6350124, 5630124, 6530124,
        1356024, 3156024, 1536024, 5136024, 3516024, 5316024, 1365024, 3165024, 1635024, 6135024, 3615024, 6315024,
        1563024, 5163024, 1653024, 6153024, 5613024, 6513024, 3561024, 5361024, 3651024, 6351024, 5631024, 6531024,
        235614,  2035614, 325614,  3025614, 2305614, 3205614, 253614,  2053614, 523614,  5023614, 2503614, 5203614,
        352614,  3052614, 532614,  5032614, 3502614, 5302614, 2350614, 3250614, 2530614, 5230614, 3520614, 5320614,
        236514,  2036514, 326514,  3026514, 2306514, 3206514, 263514,  2063514, 623514,  6023514, 2603514, 6203514,
        362514,  3062514, 632514,  6032514, 3602514, 6302514, 2360514, 3260514, 2630514, 6230514, 3620514, 6320514,
        256314,  2056314, 526314,  5026314, 2506314, 5206314, 265314,  2065314, 625314,  6025314, 2605314, 6205314,
        562314,  5062314, 652314,  6052314, 5602314, 6502314, 2560314, 5260314, 2650314, 6250314, 5620314, 6520314,
        356214,  3056214, 536214,  5036214, 3506214, 5306214, 365214,  3065214, 635214,  6035214, 3605214, 6305214,
        563214,  5063214, 653214,  6053214, 5603214, 6503214, 3560214, 5360214, 3650214, 6350214, 5630214, 6530214,
        2356014, 3256014, 2536014, 5236014, 3526014, 5326014, 2365014, 3265014, 2635014, 6235014, 3625014, 6325014,
        2563014, 5263014, 2653014, 6253014, 5623014, 6523014, 3562014, 5362014, 3652014, 6352014, 5632014, 6532014,
        1235604, 2135604, 1325604, 3125604, 2315604, 3215604, 1253604, 2153604, 1523604, 5123604, 2513604, 5213604,
        1352604, 3152604, 1532604, 5132604, 3512604, 5312604, 2351604, 3251604, 2531604, 5231604, 3521604, 5321604,
        1236504, 2136504, 1326504, 3126504, 2316504, 3216504, 1263504, 2163504, 1623504, 6123504, 2613504, 6213504,
        1362504, 3162504, 1632504, 6132504, 3612504, 6312504, 2361504, 3261504, 2631504, 6231504, 3621504, 6321504,
        1256304, 2156304, 1526304, 5126304, 2516304, 5216304, 1265304, 2165304, 1625304, 6125304, 2615304, 6215304,
        1562304, 5162304, 1652304, 6152304, 5612304, 6512304, 2561304, 5261304, 2651304, 6251304, 5621304, 6521304,
        1356204, 3156204, 1536204, 5136204, 3516204, 5316204, 1365204, 3165204, 1635204, 6135204, 3615204, 6315204,
        1563204, 5163204, 1653204, 6153204, 5613204, 6513204, 3561204, 5361204, 3651204, 6351204, 5631204, 6531204,
        2356104, 3256104, 2536104, 5236104, 3526104, 5326104, 2365104, 3265104, 2635104, 6235104, 3625104, 6325104,
        2563104, 5263104, 2653104, 6253104, 5623104, 6523104, 3562104, 5362104, 3652104, 6352104, 5632104, 6532104,
        124563,  1024563, 214563,  2014563, 1204563, 2104563, 142563,  1042563, 412563,  4012563, 1402563, 4102563,
        241563,  2041563, 421563,  4021563, 2401563, 4201563, 1240563, 2140563, 1420563, 4120563, 2410563, 4210563,
        125463,  1025463, 215463,  2015463, 1205463, 2105463, 152463,  1052463, 512463,  5012463, 1502463, 5102463,
        251463,  2051463, 521463,  5021463, 2501463, 5201463, 1250463, 2150463, 1520463, 5120463, 2510463, 5210463,
        145263,  1045263, 415263,  4015263, 1405263, 4105263, 154263,  1054263, 514263,  5014263, 1504263, 5104263,
        451263,  4051263, 541263,  5041263, 4501263, 5401263, 1450263, 4150263, 1540263, 5140263, 4510263, 5410263,
        245163,  2045163, 425163,  4025163, 2405163, 4205163, 254163,  2054163, 524163,  5024163, 2504163, 5204163,
        452163,  4052163, 542163,  5042163, 4502163, 5402163, 2450163, 4250163, 2540163, 5240163, 4520163, 5420163,
        1245063, 2145063, 1425063, 4125063, 2415063, 4215063, 1254063, 2154063, 1524063, 5124063, 2514063, 5214063,
        1452063, 4152063, 1542063, 5142063, 4512063, 5412063, 2451063, 4251063, 2541063, 5241063, 4521063, 5421063,
        124653,  1024653, 214653,  2014653, 1204653, 2104653, 142653,  1042653, 412653,  4012653, 1402653, 4102653,
        241653,  2041653, 421653,  4021653, 2401653, 4201653, 1240653, 2140653, 1420653, 4120653, 2410653, 4210653,
        126453,  1026453, 216453,  2016453, 1206453, 2106453, 162453,  1062453, 612453,  6012453, 1602453, 6102453,
        261453,  2061453, 621453,  6021453, 2601453, 6201453, 1260453, 2160453, 1620453, 6120453, 2610453, 6210453,
        146253,  1046253, 416253,  4016253, 1406253, 4106253, 164253,  1064253, 614253,  6014253, 1604253, 6104253,
        461253,  4061253, 641253,  6041253, 4601253, 6401253, 1460253, 4160253, 1640253, 6140253, 4610253, 6410253,
        246153,  2046153, 426153,  4026153, 2406153, 4206153, 264153,  2064153, 624153,  6024153, 2604153, 6204153,
        462153,  4062153, 642153,  6042153, 4602153, 6402153, 2460153, 4260153, 2640153, 6240153, 4620153, 6420153,
        1246053, 2146053, 1426053, 4126053, 2416053, 4216053, 1264053, 2164053, 1624053, 6124053, 2614053, 6214053,
        1462053, 4162053, 1642053, 6142053, 4612053, 6412053, 2461053, 4261053, 2641053, 6241053, 4621053, 6421053,
        125643,  1025643, 215643,  2015643, 1205643, 2105643, 152643,  1052643, 512643,  5012643, 1502643, 5102643,
        251643,  2051643, 521643,  5021643, 2501643, 5201643, 1250643, 2150643, 1520643, 5120643, 2510643, 5210643,
        126543,  1026543, 216543,  2016543, 1206543, 2106543, 162543,  1062543, 612543,  6012543, 1602543, 6102543,
        261543,  2061543, 621543,  6021543, 2601543, 6201543, 1260543, 2160543, 1620543, 6120543, 2610543, 6210543,
        156243,  1056243, 516243,  5016243, 1506243, 5106243, 165243,  1065243, 615243,  6015243, 1605243, 6105243,
        561243,  5061243, 651243,  6051243, 5601243, 6501243, 1560243, 5160243, 1650243, 6150243, 5610243, 6510243,
        256143,  2056143, 526143,  5026143, 2506143, 5206143, 265143,  2065143, 625143,  6025143, 2605143, 6205143,
        562143,  5062143, 652143,  6052143, 5602143, 6502143, 2560143, 5260143, 2650143, 6250143, 5620143, 6520143,
        1256043, 2156043, 1526043, 5126043, 2516043, 5216043, 1265043, 2165043, 1625043, 6125043, 2615043, 6215043,
        1562043, 5162043, 1652043, 6152043, 5612043, 6512043, 2561043, 5261043, 2651043, 6251043, 5621043, 6521043,
        145623,  1045623, 415623,  4015623, 1405623, 4105623, 154623,  1054623, 514623,  5014623, 1504623, 5104623,
        451623,  4051623, 541623,  5041623, 4501623, 5401623, 1450623, 4150623, 1540623, 5140623, 4510623, 5410623,
        146523,  1046523, 416523,  4016523, 1406523, 4106523, 164523,  1064523, 614523,  6014523, 1604523, 6104523,
        461523,  4061523, 641523,  6041523, 4601523, 6401523, 1460523, 4160523, 1640523, 6140523, 4610523, 6410523,
        156423,  1056423, 516423,  5016423, 1506423, 5106423, 165423,  1065423, 615423,  6015423, 1605423, 6105423,
        561423,  5061423, 651423,  6051423, 5601423, 6501423, 1560423, 5160423, 1650423, 6150423, 5610423, 6510423,
        456123,  4056123, 546123,  5046123, 4506123, 5406123, 465123,  4065123, 645123,  6045123, 4605123, 6405123,
        564123,  5064123, 654123,  6054123, 5604123, 6504123, 4560123, 5460123, 4650123, 6450123, 5640123, 6540123,
        1456023, 4156023, 1546023, 5146023, 4516023, 5416023, 1465023, 4165023, 1645023, 6145023, 4615023, 6415023,
        1564023, 5164023, 1654023, 6154023, 5614023, 6514023, 4561023, 5461023, 4651023, 6451023, 5641023, 6541023,
        245613,  2045613, 425613,  4025613, 2405613, 4205613, 254613,  2054613, 524613,  5024613, 2504613, 5204613,
        452613,  4052613, 542613,  5042613, 4502613, 5402613, 2450613, 4250613, 2540613, 5240613, 4520613, 5420613,
        246513,  2046513, 426513,  4026513, 2406513, 4206513, 264513,  2064513, 624513,  6024513, 2604513, 6204513,
        462513,  4062513, 642513,  6042513, 4602513, 6402513, 2460513, 4260513, 2640513, 6240513, 4620513, 6420513,
        256413,  2056413, 526413,  5026413, 2506413, 5206413, 265413,  2065413, 625413,  6025413, 2605413, 6205413,
        562413,  5062413, 652413,  6052413, 5602413, 6502413, 2560413, 5260413, 2650413, 6250413, 5620413, 6520413,
        456213,  4056213, 546213,  5046213, 4506213, 5406213, 465213,  4065213, 645213,  6045213, 4605213, 6405213,
        564213,  5064213, 654213,  6054213, 5604213, 6504213, 4560213, 5460213, 4650213, 6450213, 5640213, 6540213,
        2456013, 4256013, 2546013, 5246013, 4526013, 5426013, 2465013, 4265013, 2645013, 6245013, 4625013, 6425013,
        2564013, 5264013, 2654013, 6254013, 5624013, 6524013, 4562013, 5462013, 4652013, 6452013, 5642013, 6542013,
        1245603, 2145603, 1425603, 4125603, 2415603, 4215603, 1254603, 2154603, 1524603, 5124603, 2514603, 5214603,
        1452603, 4152603, 1542603, 5142603, 4512603, 5412603, 2451603, 4251603, 2541603, 5241603, 4521603, 5421603,
        1246503, 2146503, 1426503, 4126503, 2416503, 4216503, 1264503, 2164503, 1624503, 6124503, 2614503, 6214503,
        1462503, 4162503, 1642503, 6142503, 4612503, 6412503, 2461503, 4261503, 2641503, 6241503, 4621503, 6421503,
        1256403, 2156403, 1526403, 5126403, 2516403, 5216403, 1265403, 2165403, 1625403, 6125403, 2615403, 6215403,
        1562403, 5162403, 1652403, 6152403, 5612403, 6512403, 2561403, 5261403, 2651403, 6251403, 5621403, 6521403,
        1456203, 4156203, 1546203, 5146203, 4516203, 5416203, 1465203, 4165203, 1645203, 6145203, 4615203, 6415203,
        1564203, 5164203, 1654203, 6154203, 5614203, 6514203, 4561203, 5461203, 4651203, 6451203, 5641203, 6541203,
        2456103, 4256103, 2546103, 5246103, 4526103, 5426103, 2465103, 4265103, 2645103, 6245103, 4625103, 6425103,
        2564103, 5264103, 2654103, 6254103, 5624103, 6524103, 4562103, 5462103, 4652103, 6452103, 5642103, 6542103,
        134562,  1034562, 314562,  3014562, 1304562, 3104562, 143562,  1043562, 413562,  4013562, 1403562, 4103562,
        341562,  3041562, 431562,  4031562, 3401562, 4301562, 1340562, 3140562, 1430562, 4130562, 3410562, 4310562,
        135462,  1035462, 315462,  3015462, 1305462, 3105462, 153462,  1053462, 513462,  5013462, 1503462, 5103462,
        351462,  3051462, 531462,  5031462, 3501462, 5301462, 1350462, 3150462, 1530462, 5130462, 3510462, 5310462,
        145362,  1045362, 415362,  4015362, 1405362, 4105362, 154362,  1054362, 514362,  5014362, 1504362, 5104362,
        451362,  4051362, 541362,  5041362, 4501362, 5401362, 1450362, 4150362, 1540362, 5140362, 4510362, 5410362,
        345162,  3045162, 435162,  4035162, 3405162, 4305162, 354162,  3054162, 534162,  5034162, 3504162, 5304162,
        453162,  4053162, 543162,  5043162, 4503162, 5403162, 3450162, 4350162, 3540162, 5340162, 4530162, 5430162,
        1345062, 3145062, 1435062, 4135062, 3415062, 4315062, 1354062, 3154062, 1534062, 5134062, 3514062, 5314062,
        1453062, 4153062, 1543062, 5143062, 4513062, 5413062, 3451062, 4351062, 3541062, 5341062, 4531062, 5431062,
        134652,  1034652, 314652,  3014652, 1304652, 3104652, 143652,  1043652, 413652,  4013652, 1403652, 4103652,
        341652,  3041652, 431652,  4031652, 3401652, 4301652, 1340652, 3140652, 1430652, 4130652, 3410652, 4310652,
        136452,  1036452, 316452,  3016452, 1306452, 3106452, 163452,  1063452, 613452,  6013452, 1603452, 6103452,
        361452,  3061452, 631452,  6031452, 3601452, 6301452, 1360452, 3160452, 1630452, 6130452, 3610452, 6310452,
        146352,  1046352, 416352,  4016352, 1406352, 4106352, 164352,  1064352, 614352,  6014352, 1604352, 6104352,
        461352,  4061352, 641352,  6041352, 4601352, 6401352, 1460352, 4160352, 1640352, 6140352, 4610352, 6410352,
        346152,  3046152, 436152,  4036152, 3406152, 4306152, 364152,  3064152, 634152,  6034152, 3604152, 6304152,
        463152,  4063152, 643152,  6043152, 4603152, 6403152, 3460152, 4360152, 3640152, 6340152, 4630152, 6430152,
        1346052, 3146052, 1436052, 4136052, 3416052, 4316052, 1364052, 3164052, 1634052, 6134052, 3614052, 6314052,
        1463052, 4163052, 1643052, 6143052, 4613052, 6413052, 3461052, 4361052, 3641052, 6341052, 4631052, 6431052,
        135642,  1035642, 315642,  3015642, 1305642, 3105642, 153642,  1053642, 513642,  5013642, 1503642, 5103642,
        351642,  3051642, 531642,  5031642, 3501642, 5301642, 1350642, 3150642, 1530642, 5130642, 3510642, 5310642,
        136542,  1036542, 316542,  3016542, 1306542, 3106542, 163542,  1063542, 613542,  6013542, 1603542, 6103542,
        361542,  3061542, 631542,  6031542, 3601542, 6301542, 1360542, 3160542, 1630542, 6130542, 3610542, 6310542,
        156342,  1056342, 516342,  5016342, 1506342, 5106342, 165342,  1065342, 615342,  6015342, 1605342, 6105342,
        561342,  5061342, 651342,  6051342, 5601342, 6501342, 1560342, 5160342, 1650342, 6150342, 5610342, 6510342,
        356142,  3056142, 536142,  5036142, 3506142, 5306142, 365142,  3065142, 635142,  6035142, 3605142, 6305142,
        563142,  5063142, 653142,  6053142, 5603142, 6503142, 3560142, 5360142, 3650142, 6350142, 5630142, 6530142,
        1356042, 3156042, 1536042, 5136042, 3516042, 5316042, 1365042, 3165042, 1635042, 6135042, 3615042, 6315042,
        1563042, 5163042, 1653042, 6153042, 5613042, 6513042, 3561042, 5361042, 3651042, 6351042, 5631042, 6531042,
        145632,  1045632, 415632,  4015632, 1405632, 4105632, 154632,  1054632, 514632,  5014632, 1504632, 5104632,
        451632,  4051632, 541632,  5041632, 4501632, 5401632, 1450632, 4150632, 1540632, 5140632, 4510632, 5410632,
        146532,  1046532, 416532,  4016532, 1406532, 4106532, 164532,  1064532, 614532,  6014532, 1604532, 6104532,
        461532,  4061532, 641532,  6041532, 4601532, 6401532, 1460532, 4160532, 1640532, 6140532, 4610532, 6410532,
        156432,  1056432, 516432,  5016432, 1506432, 5106432, 165432,  1065432, 615432,  6015432, 1605432, 6105432,
        561432,  5061432, 651432,  6051432, 5601432, 6501432, 1560432, 5160432, 1650432, 6150432, 5610432, 6510432,
        456132,  4056132, 546132,  5046132, 4506132, 5406132, 465132,  4065132, 645132,  6045132, 4605132, 6405132,
        564132,  5064132, 654132,  6054132, 5604132, 6504132, 4560132, 5460132, 4650132, 6450132, 5640132, 6540132,
        1456032, 4156032, 1546032, 5146032, 4516032, 5416032, 1465032, 4165032, 1645032, 6145032, 4615032, 6415032,
        1564032, 5164032, 1654032, 6154032, 5614032, 6514032, 4561032, 5461032, 4651032, 6451032, 5641032, 6541032,
        345612,  3045612, 435612,  4035612, 3405612, 4305612, 354612,  3054612, 534612,  5034612, 3504612, 5304612,
        453612,  4053612, 543612,  5043612, 4503612, 5403612, 3450612, 4350612, 3540612, 5340612, 4530612, 5430612,
        346512,  3046512, 436512,  4036512, 3406512, 4306512, 364512,  3064512, 634512,  6034512, 3604512, 6304512,
        463512,  4063512, 643512,  6043512, 4603512, 6403512, 3460512, 4360512, 3640512, 6340512, 4630512, 6430512,
        356412,  3056412, 536412,  5036412, 3506412, 5306412, 365412,  3065412, 635412,  6035412, 3605412, 6305412,
        563412,  5063412, 653412,  6053412, 5603412, 6503412, 3560412, 5360412, 3650412, 6350412, 5630412, 6530412,
        456312,  4056312, 546312,  5046312, 4506312, 5406312, 465312,  4065312, 645312,  6045312, 4605312, 6405312,
        564312,  5064312, 654312,  6054312, 5604312, 6504312, 4560312, 5460312, 4650312, 6450312, 5640312, 6540312,
        3456012, 4356012, 3546012, 5346012, 4536012, 5436012, 3465012, 4365012, 3645012, 6345012, 4635012, 6435012,
        3564012, 5364012, 3654012, 6354012, 5634012, 6534012, 4563012, 5463012, 4653012, 6453012, 5643012, 6543012,
        1345602, 3145602, 1435602, 4135602, 3415602, 4315602, 1354602, 3154602, 1534602, 5134602, 3514602, 5314602,
        1453602, 4153602, 1543602, 5143602, 4513602, 5413602, 3451602, 4351602, 3541602, 5341602, 4531602, 5431602,
        1346502, 3146502, 1436502, 4136502, 3416502, 4316502, 1364502, 3164502, 1634502, 6134502, 3614502, 6314502,
        1463502, 4163502, 1643502, 6143502, 4613502, 6413502, 3461502, 4361502, 3641502, 6341502, 4631502, 6431502,
        1356402, 3156402, 1536402, 5136402, 3516402, 5316402, 1365402, 3165402, 1635402, 6135402, 3615402, 6315402,
        1563402, 5163402, 1653402, 6153402, 5613402, 6513402, 3561402, 5361402, 3651402, 6351402, 5631402, 6531402,
        1456302, 4156302, 1546302, 5146302, 4516302, 5416302, 1465302, 4165302, 1645302, 6145302, 4615302, 6415302,
        1564302, 5164302, 1654302, 6154302, 5614302, 6514302, 4561302, 5461302, 4651302, 6451302, 5641302, 6541302,
        3456102, 4356102, 3546102, 5346102, 4536102, 5436102, 3465102, 4365102, 3645102, 6345102, 4635102, 6435102,
        3564102, 5364102, 3654102, 6354102, 5634102, 6534102, 4563102, 5463102, 4653102, 6453102, 5643102, 6543102,
        234561,  2034561, 324561,  3024561, 2304561, 3204561, 243561,  2043561, 423561,  4023561, 2403561, 4203561,
        342561,  3042561, 432561,  4032561, 3402561, 4302561, 2340561, 3240561, 2430561, 4230561, 3420561, 4320561,
        235461,  2035461, 325461,  3025461, 2305461, 3205461, 253461,  2053461, 523461,  5023461, 2503461, 5203461,
        352461,  3052461, 532461,  5032461, 3502461, 5302461, 2350461, 3250461, 2530461, 5230461, 3520461, 5320461,
        245361,  2045361, 425361,  4025361, 2405361, 4205361, 254361,  2054361, 524361,  5024361, 2504361, 5204361,
        452361,  4052361, 542361,  5042361, 4502361, 5402361, 2450361, 4250361, 2540361, 5240361, 4520361, 5420361,
        345261,  3045261, 435261,  4035261, 3405261, 4305261, 354261,  3054261, 534261,  5034261, 3504261, 5304261,
        453261,  4053261, 543261,  5043261, 4503261, 5403261, 3450261, 4350261, 3540261, 5340261, 4530261, 5430261,
        2345061, 3245061, 2435061, 4235061, 3425061, 4325061, 2354061, 3254061, 2534061, 5234061, 3524061, 5324061,
        2453061, 4253061, 2543061, 5243061, 4523061, 5423061, 3452061, 4352061, 3542061, 5342061, 4532061, 5432061,
        234651,  2034651, 324651,  3024651, 2304651, 3204651, 243651,  2043651, 423651,  4023651, 2403651, 4203651,
        342651,  3042651, 432651,  4032651, 3402651, 4302651, 2340651, 3240651, 2430651, 4230651, 3420651, 4320651,
        236451,  2036451, 326451,  3026451, 2306451, 3206451, 263451,  2063451, 623451,  6023451, 2603451, 6203451,
        362451,  3062451, 632451,  6032451, 3602451, 6302451, 2360451, 3260451, 2630451, 6230451, 3620451, 6320451,
        246351,  2046351, 426351,  4026351, 2406351, 4206351, 264351,  2064351, 624351,  6024351, 2604351, 6204351,
        462351,  4062351, 642351,  6042351, 4602351, 6402351, 2460351, 4260351, 2640351, 6240351, 4620351, 6420351,
        346251,  3046251, 436251,  4036251, 3406251, 4306251, 364251,  3064251, 634251,  6034251, 3604251, 6304251,
        463251,  4063251, 643251,  6043251, 4603251, 6403251, 3460251, 4360251, 3640251, 6340251, 4630251, 6430251,
        2346051, 3246051, 2436051, 4236051, 3426051, 4326051, 2364051, 3264051, 2634051, 6234051, 3624051, 6324051,
        2463051, 4263051, 2643051, 6243051, 4623051, 6423051, 3462051, 4362051, 3642051, 6342051, 4632051, 6432051,
        235641,  2035641, 325641,  3025641, 2305641, 3205641, 253641,  2053641, 523641,  5023641, 2503641, 5203641,
        352641,  3052641, 532641,  5032641, 3502641, 5302641, 2350641, 3250641, 2530641, 5230641, 3520641, 5320641,
        236541,  2036541, 326541,  3026541, 2306541, 3206541, 263541,  2063541, 623541,  6023541, 2603541, 6203541,
        362541,  3062541, 632541,  6032541, 3602541, 6302541, 2360541, 3260541, 2630541, 6230541, 3620541, 6320541,
        256341,  2056341, 526341,  5026341, 2506341, 5206341, 265341,  2065341, 625341,  6025341, 2605341, 6205341,
        562341,  5062341, 652341,  6052341, 5602341, 6502341, 2560341, 5260341, 2650341, 6250341, 5620341, 6520341,
        356241,  3056241, 536241,  5036241, 3506241, 5306241, 365241,  3065241, 635241,  6035241, 3605241, 6305241,
        563241,  5063241, 653241,  6053241, 5603241, 6503241, 3560241, 5360241, 3650241, 6350241, 5630241, 6530241,
        2356041, 3256041, 2536041, 5236041, 3526041, 5326041, 2365041, 3265041, 2635041, 6235041, 3625041, 6325041,
        2563041, 5263041, 2653041, 6253041, 5623041, 6523041, 3562041, 5362041, 3652041, 6352041, 5632041, 6532041,
        245631,  2045631, 425631,  4025631, 2405631, 4205631, 254631,  2054631, 524631,  5024631, 2504631, 5204631,
        452631,  4052631, 542631,  5042631, 4502631, 5402631, 2450631, 4250631, 2540631, 5240631, 4520631, 5420631,
        246531,  2046531, 426531,  4026531, 2406531, 4206531, 264531,  2064531, 624531,  6024531, 2604531, 6204531,
        462531,  4062531, 642531,  6042531, 4602531, 6402531, 2460531, 4260531, 2640531, 6240531, 4620531, 6420531,
        256431,  2056431, 526431,  5026431, 2506431, 5206431, 265431,  2065431, 625431,  6025431, 2605431, 6205431,
        562431,  5062431, 652431,  6052431, 5602431, 6502431, 2560431, 5260431, 2650431, 6250431, 5620431, 6520431,
        456231,  4056231, 546231,  5046231, 4506231, 5406231, 465231,  4065231, 645231,  6045231, 4605231, 6405231,
        564231,  5064231, 654231,  6054231, 5604231, 6504231, 4560231, 5460231, 4650231, 6450231, 5640231, 6540231,
        2456031, 4256031, 2546031, 5246031, 4526031, 5426031, 2465031, 4265031, 2645031, 6245031, 4625031, 6425031,
        2564031, 5264031, 2654031, 6254031, 5624031, 6524031, 4562031, 5462031, 4652031, 6452031, 5642031, 6542031,
        345621,  3045621, 435621,  4035621, 3405621, 4305621, 354621,  3054621, 534621,  5034621, 3504621, 5304621,
        453621,  4053621, 543621,  5043621, 4503621, 5403621, 3450621, 4350621, 3540621, 5340621, 4530621, 5430621,
        346521,  3046521, 436521,  4036521, 3406521, 4306521, 364521,  3064521, 634521,  6034521, 3604521, 6304521,
        463521,  4063521, 643521,  6043521, 4603521, 6403521, 3460521, 4360521, 3640521, 6340521, 4630521, 6430521,
        356421,  3056421, 536421,  5036421, 3506421, 5306421, 365421,  3065421, 635421,  6035421, 3605421, 6305421,
        563421,  5063421, 653421,  6053421, 5603421, 6503421, 3560421, 5360421, 3650421, 6350421, 5630421, 6530421,
        456321,  4056321, 546321,  5046321, 4506321, 5406321, 465321,  4065321, 645321,  6045321, 4605321, 6405321,
        564321,  5064321, 654321,  6054321, 5604321, 6504321, 4560321, 5460321, 4650321, 6450321, 5640321, 6540321,
        3456021, 4356021, 3546021, 5346021, 4536021, 5436021, 3465021, 4365021, 3645021, 6345021, 4635021, 6435021,
        3564021, 5364021, 3654021, 6354021, 5634021, 6534021, 4563021, 5463021, 4653021, 6453021, 5643021, 6543021,
        2345601, 3245601, 2435601, 4235601, 3425601, 4325601, 2354601, 3254601, 2534601, 5234601, 3524601, 5324601,
        2453601, 4253601, 2543601, 5243601, 4523601, 5423601, 3452601, 4352601, 3542601, 5342601, 4532601, 5432601,
        2346501, 3246501, 2436501, 4236501, 3426501, 4326501, 2364501, 3264501, 2634501, 6234501, 3624501, 6324501,
        2463501, 4263501, 2643501, 6243501, 4623501, 6423501, 3462501, 4362501, 3642501, 6342501, 4632501, 6432501,
        2356401, 3256401, 2536401, 5236401, 3526401, 5326401, 2365401, 3265401, 2635401, 6235401, 3625401, 6325401,
        2563401, 5263401, 2653401, 6253401, 5623401, 6523401, 3562401, 5362401, 3652401, 6352401, 5632401, 6532401,
        2456301, 4256301, 2546301, 5246301, 4526301, 5426301, 2465301, 4265301, 2645301, 6245301, 4625301, 6425301,
        2564301, 5264301, 2654301, 6254301, 5624301, 6524301, 4562301, 5462301, 4652301, 6452301, 5642301, 6542301,
        3456201, 4356201, 3546201, 5346201, 4536201, 5436201, 3465201, 4365201, 3645201, 6345201, 4635201, 6435201,
        3564201, 5364201, 3654201, 6354201, 5634201, 6534201, 4563201, 5463201, 4653201, 6453201, 5643201, 6543201,
        1234560, 2134560, 1324560, 3124560, 2314560, 3214560, 1243560, 2143560, 1423560, 4123560, 2413560, 4213560,
        1342560, 3142560, 1432560, 4132560, 3412560, 4312560, 2341560, 3241560, 2431560, 4231560, 3421560, 4321560,
        1235460, 2135460, 1325460, 3125460, 2315460, 3215460, 1253460, 2153460, 1523460, 5123460, 2513460, 5213460,
        1352460, 3152460, 1532460, 5132460, 3512460, 5312460, 2351460, 3251460, 2531460, 5231460, 3521460, 5321460,
        1245360, 2145360, 1425360, 4125360, 2415360, 4215360, 1254360, 2154360, 1524360, 5124360, 2514360, 5214360,
        1452360, 4152360, 1542360, 5142360, 4512360, 5412360, 2451360, 4251360, 2541360, 5241360, 4521360, 5421360,
        1345260, 3145260, 1435260, 4135260, 3415260, 4315260, 1354260, 3154260, 1534260, 5134260, 3514260, 5314260,
        1453260, 4153260, 1543260, 5143260, 4513260, 5413260, 3451260, 4351260, 3541260, 5341260, 4531260, 5431260,
        2345160, 3245160, 2435160, 4235160, 3425160, 4325160, 2354160, 3254160, 2534160, 5234160, 3524160, 5324160,
        2453160, 4253160, 2543160, 5243160, 4523160, 5423160, 3452160, 4352160, 3542160, 5342160, 4532160, 5432160,
        1234650, 2134650, 1324650, 3124650, 2314650, 3214650, 1243650, 2143650, 1423650, 4123650, 2413650, 4213650,
        1342650, 3142650, 1432650, 4132650, 3412650, 4312650, 2341650, 3241650, 2431650, 4231650, 3421650, 4321650,
        1236450, 2136450, 1326450, 3126450, 2316450, 3216450, 1263450, 2163450, 1623450, 6123450, 2613450, 6213450,
        1362450, 3162450, 1632450, 6132450, 3612450, 6312450, 2361450, 3261450, 2631450, 6231450, 3621450, 6321450,
        1246350, 2146350, 1426350, 4126350, 2416350, 4216350, 1264350, 2164350, 1624350, 6124350, 2614350, 6214350,
        1462350, 4162350, 1642350, 6142350, 4612350, 6412350, 2461350, 4261350, 2641350, 6241350, 4621350, 6421350,
        1346250, 3146250, 1436250, 4136250, 3416250, 4316250, 1364250, 3164250, 1634250, 6134250, 3614250, 6314250,
        1463250, 4163250, 1643250, 6143250, 4613250, 6413250, 3461250, 4361250, 3641250, 6341250, 4631250, 6431250,
        2346150, 3246150, 2436150, 4236150, 3426150, 4326150, 2364150, 3264150, 2634150, 6234150, 3624150, 6324150,
        2463150, 4263150, 2643150, 6243150, 4623150, 6423150, 3462150, 4362150, 3642150, 6342150, 4632150, 6432150,
        1235640, 2135640, 1325640, 3125640, 2315640, 3215640, 1253640, 2153640, 1523640, 5123640, 2513640, 5213640,
        1352640, 3152640, 1532640, 5132640, 3512640, 5312640, 2351640, 3251640, 2531640, 5231640, 3521640, 5321640,
        1236540, 2136540, 1326540, 3126540, 2316540, 3216540, 1263540, 2163540, 1623540, 6123540, 2613540, 6213540,
        1362540, 3162540, 1632540, 6132540, 3612540, 6312540, 2361540, 3261540, 2631540, 6231540, 3621540, 6321540,
        1256340, 2156340, 1526340, 5126340, 2516340, 5216340, 1265340, 2165340, 1625340, 6125340, 2615340, 6215340,
        1562340, 5162340, 1652340, 6152340, 5612340, 6512340, 2561340, 5261340, 2651340, 6251340, 5621340, 6521340,
        1356240, 3156240, 1536240, 5136240, 3516240, 5316240, 1365240, 3165240, 1635240, 6135240, 3615240, 6315240,
        1563240, 5163240, 1653240, 6153240, 5613240, 6513240, 3561240, 5361240, 3651240, 6351240, 5631240, 6531240,
        2356140, 3256140, 2536140, 5236140, 3526140, 5326140, 2365140, 3265140, 2635140, 6235140, 3625140, 6325140,
        2563140, 5263140, 2653140, 6253140, 5623140, 6523140, 3562140, 5362140, 3652140, 6352140, 5632140, 6532140,
        1245630, 2145630, 1425630, 4125630, 2415630, 4215630, 1254630, 2154630, 1524630, 5124630, 2514630, 5214630,
        1452630, 4152630, 1542630, 5142630, 4512630, 5412630, 2451630, 4251630, 2541630, 5241630, 4521630, 5421630,
        1246530, 2146530, 1426530, 4126530, 2416530, 4216530, 1264530, 2164530, 1624530, 6124530, 2614530, 6214530,
        1462530, 4162530, 1642530, 6142530, 4612530, 6412530, 2461530, 4261530, 2641530, 6241530, 4621530, 6421530,
        1256430, 2156430, 1526430, 5126430, 2516430, 5216430, 1265430, 2165430, 1625430, 6125430, 2615430, 6215430,
        1562430, 5162430, 1652430, 6152430, 5612430, 6512430, 2561430, 5261430, 2651430, 6251430, 5621430, 6521430,
        1456230, 4156230, 1546230, 5146230, 4516230, 5416230, 1465230, 4165230, 1645230, 6145230, 4615230, 6415230,
        1564230, 5164230, 1654230, 6154230, 5614230, 6514230, 4561230, 5461230, 4651230, 6451230, 5641230, 6541230,
        2456130, 4256130, 2546130, 5246130, 4526130, 5426130, 2465130, 4265130, 2645130, 6245130, 4625130, 6425130,
        2564130, 5264130, 2654130, 6254130, 5624130, 6524130, 4562130, 5462130, 4652130, 6452130, 5642130, 6542130,
        1345620, 3145620, 1435620, 4135620, 3415620, 4315620, 1354620, 3154620, 1534620, 5134620, 3514620, 5314620,
        1453620, 4153620, 1543620, 5143620, 4513620, 5413620, 3451620, 4351620, 3541620, 5341620, 4531620, 5431620,
        1346520, 3146520, 1436520, 4136520, 3416520, 4316520, 1364520, 3164520, 1634520, 6134520, 3614520, 6314520,
        1463520, 4163520, 1643520, 6143520, 4613520, 6413520, 3461520, 4361520, 3641520, 6341520, 4631520, 6431520,
        1356420, 3156420, 1536420, 5136420, 3516420, 5316420, 1365420, 3165420, 1635420, 6135420, 3615420, 6315420,
        1563420, 5163420, 1653420, 6153420, 5613420, 6513420, 3561420, 5361420, 3651420, 6351420, 5631420, 6531420,
        1456320, 4156320, 1546320, 5146320, 4516320, 5416320, 1465320, 4165320, 1645320, 6145320, 4615320, 6415320,
        1564320, 5164320, 1654320, 6154320, 5614320, 6514320, 4561320, 5461320, 4651320, 6451320, 5641320, 6541320,
        3456120, 4356120, 3546120, 5346120, 4536120, 5436120, 3465120, 4365120, 3645120, 6345120, 4635120, 6435120,
        3564120, 5364120, 3654120, 6354120, 5634120, 6534120, 4563120, 5463120, 4653120, 6453120, 5643120, 6543120,
        2345610, 3245610, 2435610, 4235610, 3425610, 4325610, 2354610, 3254610, 2534610, 5234610, 3524610, 5324610,
        2453610, 4253610, 2543610, 5243610, 4523610, 5423610, 3452610, 4352610, 3542610, 5342610, 4532610, 5432610,
        2346510, 3246510, 2436510, 4236510, 3426510, 4326510, 2364510, 3264510, 2634510, 6234510, 3624510, 6324510,
        2463510, 4263510, 2643510, 6243510, 4623510, 6423510, 3462510, 4362510, 3642510, 6342510, 4632510, 6432510,
        2356410, 3256410, 2536410, 5236410, 3526410, 5326410, 2365410, 3265410, 2635410, 6235410, 3625410, 6325410,
        2563410, 5263410, 2653410, 6253410, 5623410, 6523410, 3562410, 5362410, 3652410, 6352410, 5632410, 6532410,
        2456310, 4256310, 2546310, 5246310, 4526310, 5426310, 2465310, 4265310, 2645310, 6245310, 4625310, 6425310,
        2564310, 5264310, 2654310, 6254310, 5624310, 6524310, 4562310, 5462310, 4652310, 6452310, 5642310, 6542310,
        3456210, 4356210, 3546210, 5346210, 4536210, 5436210, 3465210, 4365210, 3645210, 6345210, 4635210, 6435210,
        3564210, 5364210, 3654210, 6354210, 5634210, 6534210, 4563210, 5463210, 4653210, 6453210, 5643210, 6543210};
    std::map<uint64_t, int> expected;
    for (std::size_t i = 0; i < 5040; i++) expected[pre_expected[i]] = 0;  // flags are 0, everything is symmetric here

    VERIFY(isDynGroup(group));
    VERIFY_IS_EQUAL(group.size(), 5040u);
    VERIFY_IS_EQUAL(group.globalFlags(), 0);
    group.apply<checkIdx, int>(identity7, 0, found, expected);
    VERIFY_IS_EQUAL(found.size(), 5040u);
  }
}

static void test_tensor_epsilon() {
  SGroup<AntiSymmetry<0, 1>, AntiSymmetry<1, 2>> sym;
  Tensor<int, 3> epsilon(3, 3, 3);

  epsilon.setZero();
  sym(epsilon, 0, 1, 2) = 1;

  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      for (int k = 0; k < 3; k++) {
        VERIFY_IS_EQUAL((epsilon(i, j, k)), (-(j - i) * (k - j) * (i - k) / 2));
      }
    }
  }
}

static void test_tensor_sym() {
  SGroup<Symmetry<0, 1>, Symmetry<2, 3>> sym;
  Tensor<int, 4> t(10, 10, 10, 10);

  t.setZero();

  for (int l = 0; l < 10; l++) {
    for (int k = l; k < 10; k++) {
      for (int j = 0; j < 10; j++) {
        for (int i = j; i < 10; i++) {
          sym(t, i, j, k, l) = (i + j) * (k + l);
        }
      }
    }
  }

  for (int l = 0; l < 10; l++) {
    for (int k = 0; k < 10; k++) {
      for (int j = 0; j < 10; j++) {
        for (int i = 0; i < 10; i++) {
          VERIFY_IS_EQUAL((t(i, j, k, l)), ((i + j) * (k + l)));
        }
      }
    }
  }
}

static void test_tensor_asym() {
  SGroup<AntiSymmetry<0, 1>, AntiSymmetry<2, 3>> sym;
  Tensor<int, 4> t(10, 10, 10, 10);

  t.setZero();

  for (int l = 0; l < 10; l++) {
    for (int k = l + 1; k < 10; k++) {
      for (int j = 0; j < 10; j++) {
        for (int i = j + 1; i < 10; i++) {
          sym(t, i, j, k, l) = ((i * j) + (k * l));
        }
      }
    }
  }

  for (int l = 0; l < 10; l++) {
    for (int k = 0; k < 10; k++) {
      for (int j = 0; j < 10; j++) {
        for (int i = 0; i < 10; i++) {
          if (i < j && k < l)
            VERIFY_IS_EQUAL((t(i, j, k, l)), (((i * j) + (k * l))));
          else if (i > j && k > l)
            VERIFY_IS_EQUAL((t(i, j, k, l)), (((i * j) + (k * l))));
          else if (i < j && k > l)
            VERIFY_IS_EQUAL((t(i, j, k, l)), (-((i * j) + (k * l))));
          else if (i > j && k < l)
            VERIFY_IS_EQUAL((t(i, j, k, l)), (-((i * j) + (k * l))));
          else
            VERIFY_IS_EQUAL((t(i, j, k, l)), 0);
        }
      }
    }
  }
}

static void test_tensor_dynsym() {
  DynamicSGroup sym;
  sym.addSymmetry(0, 1);
  sym.addSymmetry(2, 3);
  Tensor<int, 4> t(10, 10, 10, 10);

  t.setZero();

  for (int l = 0; l < 10; l++) {
    for (int k = l; k < 10; k++) {
      for (int j = 0; j < 10; j++) {
        for (int i = j; i < 10; i++) {
          sym(t, i, j, k, l) = (i + j) * (k + l);
        }
      }
    }
  }

  for (int l = 0; l < 10; l++) {
    for (int k = 0; k < 10; k++) {
      for (int j = 0; j < 10; j++) {
        for (int i = 0; i < 10; i++) {
          VERIFY_IS_EQUAL((t(i, j, k, l)), ((i + j) * (k + l)));
        }
      }
    }
  }
}

static void test_tensor_randacc() {
  SGroup<Symmetry<0, 1>, Symmetry<2, 3>> sym;
  Tensor<int, 4> t(10, 10, 10, 10);

  t.setZero();

  // set elements 1 million times, that way we access the
  // entire matrix
  for (int n = 0; n < 1000000; n++) {
    int i = rand() % 10;
    int j = rand() % 10;
    int k = rand() % 10;
    int l = rand() % 10;
    // only access those indices in a given order
    if (i < j) std::swap(i, j);
    if (k < l) std::swap(k, l);
    sym(t, i, j, k, l) = (i + j) * (k + l);
  }

  for (int l = 0; l < 10; l++) {
    for (int k = 0; k < 10; k++) {
      for (int j = 0; j < 10; j++) {
        for (int i = 0; i < 10; i++) {
          VERIFY_IS_EQUAL((t(i, j, k, l)), ((i + j) * (k + l)));
        }
      }
    }
  }
}

EIGEN_DECLARE_TEST(cxx11_tensor_symmetry) {
  CALL_SUBTEST(test_symgroups_static());
  CALL_SUBTEST(test_symgroups_dynamic());
  CALL_SUBTEST(test_symgroups_selection());
  CALL_SUBTEST(test_tensor_epsilon());
  CALL_SUBTEST(test_tensor_sym());
  CALL_SUBTEST(test_tensor_asym());
  CALL_SUBTEST(test_tensor_dynsym());
  CALL_SUBTEST(test_tensor_randacc());
}

/*
 * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
 */
